﻿using System;

namespace 面向对象_扩展方法
{
    class Program
    {

        static void Main(string[] args)
        {
            string str = "123";
            var value = str.ToInt32(50);
            Console.WriteLine(value);

            string str1 = "张三*李四*王五";
            var value1 = str1.GetName('*',2);
            Console.WriteLine(value1);

            Person p = new Person("小边");
            p.Eat();
            p.Fly();
            //p.Fly1();
            PersonEX.Fly1(p);//this 存在可以用实例来访问方法，没有this只能用类名去访问
        }
    }
    // 扩展方法：是对类类型实例的能力进行扩展的一直方式，它不会对原来的类进行修改
    // 扩展方法缺点：
    // 1. 不能访问实例中的私有成员
    // 2. 访问级别比原生的要低，如果重名则覆盖（原类型存在与扩展方法同名的函数则只会调用原生类型中的方法）
    // 扩展方法的风险：当原生类类型中出现同名方法时，扩展方法被覆盖，但是 IDE 不会报错，如果不注意，扩展方法随时可能失效而不能被感知
    // 扩展方法的语法：必须在静态类中，必须是静态方法、首个参数使用 this 关键字,然后是类型，然后是类型实例(操作对象 ：target)
    // 如果传其他参数，接在 this 声明的参数的后方。


    // 用于存放扩展方法的类 一般使用 Ex 结尾。Ex ：extension , 类名前半部分使用你想扩展的类类型的名称
    //  测试对形如 string 这样的定义在 dll 里面的类型的实例进行方法扩展
    static class StringEx//如果是扩展方法在类名后加Ex
    {
        public static int ToInt32(this string targat,int data)//扩展了一个将string转换成int类型并相加的方法
        {
            var value = Convert.ToInt32(targat);
            value += data;
            return value;
        }
        // 假设对类似于 ”小A|35|dd“
        public static string GetName(this string target, char separate = '|', int index = 0)
        {
            // split :分割
            string name = target.Split(separate)[index];//Split方法将string类型可以用数组的形式进行访问
            return name;
        }
    }
    class Person
    {
       public  string name;
        public Person(string name) => this.name = name;
        public void Eat()
        {
            Console.WriteLine($"{name}在吃饭，但是我想飞");
        }
        // 如果 Person 中出现 Fly 方法，则扩展方法 PersonEx.Fly 将失效.
        public void Fly()
        {
            Console.WriteLine($"{name}在飞");
        }
    }
   static class PersonEX
    {
        // 编译器生成的中间语言 (IL) 会将代码转换为对静态方法的调用。 因此，并未真正违反封装原则。
        // 只需要记住扩展方法这种写法即可，遵守 C# 的游戏规则
        //  写 this 与不写 this 的同名同参数的方法属于同于一个。
        //  this 存在的意义：约定如果标记了 this ，就可以通过第一个参数的实例来访问这个方法
        public static void Fly(this Person targat)
        {
            Console.WriteLine($"{targat.name}可以飞喽！");
        }
        public static void Fly1(Person targat)
        {
            Console.WriteLine($"{targat.name}又飞了！");
        }
    }
    // 接口的扩展方法
    interface IEatable
    {
        void Eat();
    }
    public static class IEatableEx
    {
        internal static void EatPlus(this IEatable target) => Console.WriteLine($"{target} 狂吃一吨");
    }
    class Student : IEatable
    {
        string name;
        public Student(string name) => this.name = name;
        public void Eat() => Console.WriteLine($"{name} 吃一顿");
        public override string ToString() => name;
    }

}
